/**
 * @file FreeRTOS_app.c
 * @author liufeng (liufeng@injoinic.com)
 * @brief FreeRTOS task.
 * @version 0.1
 * @date 2024-11-07
 *
 * @copyright Copyright (c) 2024  injoinic
 *
 */

#include "FreeRTOS_app.h"
#include "FreeRTOS.h"
#include "elog.h"
#include "main.h"
#include "queue.h"
#include "semphr.h"
#include "task.h"

TaskHandle_t StartTask_Handle = NULL;          // 用于任务创建
TaskHandle_t ADCStartTask_Handle = NULL;       // 用于ADC采样逻辑
TaskHandle_t ADCPrintTask_Handle = NULL;       // 用于ADC数据打印

QueueHandle_t ADCBufferQueue_Handle = NULL;    // 用于从ADCStart传递消息到ADCPrint

SemaphoreHandle_t ADCSyncSemphr_Handle = NULL; // 用于ADC转换和ADC打印任务的同步

void StartTask(void* argument);
void ADCStartTask(void* argument);
void ADCPrintTask(void* argument);

void FreeRTOS_app()
{
    BaseType_t xReturn = pdPASS;
    xReturn = xTaskCreate(StartTask, "StartTask", 128, NULL, 1, &StartTask_Handle);
    configASSERT(xReturn);

    vTaskStartScheduler();
}

/* -------------------------------------------------------------------------- */
/*                                   start任务                                 */
/* -------------------------------------------------------------------------- */

void StartTask(void* argument)
{
    taskENTER_CRITICAL();                                       // 进入临界区

    ADCBufferQueue_Handle = xQueueCreate(5, sizeof(uint16_t*)); // 存放ADC buffer指针
    configASSERT(ADCBufferQueue_Handle);

    ADCSyncSemphr_Handle = xSemaphoreCreateBinary(); // 用于ADC转换和ADC打印任务的同步
    configASSERT(ADCSyncSemphr_Handle);

    BaseType_t xReturn = pdPASS;
    /* 创建ADCStartTask */
    xReturn = xTaskCreate(ADCStartTask, "ADCStartTask", 512, NULL, 3, &ADCStartTask_Handle);
    configASSERT(xReturn);

    /* 创建ADCPrintTask */
    xReturn = xTaskCreate(ADCPrintTask, "ADCPrintTask", 512, NULL, 4, &ADCPrintTask_Handle);
    configASSERT(xReturn);

    vTaskDelete(StartTask_Handle); // 使命完成，删除

    taskEXIT_CRITICAL();           // 退出临界区
}

/* -------------------------------------------------------------------------- */
/*                                 ADCStart任务                                */
/* -------------------------------------------------------------------------- */

uint16_t adc_buff1[4] = {0}; // 缓冲区1
uint16_t adc_buff2[4] = {0}; // 缓冲区2

void ADCStartTask(void* argument)
{
    xSemaphoreGive(ADCSyncSemphr_Handle);
    // 开始第一次ADC采样
    LL_ADC_REG_StartConversionSWStart(ADC1);
    while (1) {
        ulTaskNotifyTake(pdTRUE, portMAX_DELAY);

        uint16_t* p_adcbuffer = NULL; // 传引用
        if (LL_DMA_GetCurrentTargetMem(DMA2, LL_DMA_STREAM_0)) {
            p_adcbuffer = adc_buff1;  // 切换到Memory1，处理Memory0
            // log_a("DMA Buffer1's ADC Value:");
        }
        else {
            p_adcbuffer = adc_buff2; // 切换到Memory0，处理Memory1
            // log_a("DMA Buffer2's ADC Value:");
        }
        // 发送消息到ADCPrint任务
        xQueueSend(ADCBufferQueue_Handle, &p_adcbuffer, portMAX_DELAY);

        xSemaphoreTake(ADCSyncSemphr_Handle, portMAX_DELAY);
        LL_ADC_REG_StartConversionSWStart(ADC1);
    }
}

/**
 * @brief This function handles DMA2 stream0 global interrupt.
 */
void DMA2_Stream0_IRQHandler(void)
{
    traceISR_ENTER();
    if (LL_DMA_IsEnabledIT_TC(DMA2, LL_DMA_STREAM_0) && LL_DMA_IsActiveFlag_TC0(DMA2)) {
        LL_DMA_ClearFlag_TC0(DMA2);

        // 发送任务通知到ADCStart任务
        vTaskNotifyGiveFromISR(ADCStartTask_Handle, NULL);
    }
    traceISR_EXIT();
}

/* -------------------------------------------------------------------------- */
/*                                 ADCPrint任务                                */
/* -------------------------------------------------------------------------- */

void ADCPrintTask(void* argument)
{
    uint16_t* p_adcbuffer = NULL;
    while (1) {
        xQueueReceive(ADCBufferQueue_Handle, &p_adcbuffer, portMAX_DELAY);
        // ADC数据处理
        float adc_value1 = (float)p_adcbuffer[0] / 4095.f * 3.3;
        // 电压值打印
        // log_d("rank1: %f", adc_value1);

        xSemaphoreGive(ADCSyncSemphr_Handle);
    }
}
